# cronmon - Cron e-mail filtering and management
# Copyright (c) 2010 Crown copyright
# 
# This file is part of cronmon.
# 
# cronmon is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
# 
# cronmon is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
# 
# You should have received a copy of the GNU General Public License
# along with cronmon.  If not, see <http://www.gnu.org/licenses/>.

"""Importing e-mails into the DB"""

import re
import datetime
from hashlib import sha1
from email.parser import FeedParser

import pytz

from models import *
from cronmon.tagging.tag import tag
from cronmon.cron.templatetags.lines import truncatelines

from cronmon.tagging.filters import filter

email_re = re.compile(r'[\w.-]+@([\w.-]+)')


def find_host(msg):
    """Attempt to determine the host sending the cron e-mail"""
    from_addr = msg.get('From', '')
    mo = email_re.search(from_addr)
    if mo:
        hostname = mo.group(1)
    else:
        hostname = 'unknown host'

    recv_re = re.compile(r'by ([\w.-]+) with .*', re.I)

    received = msg.get_all('Received:', [])
    if received:
        recv = received[-1]

        mo = recv_re.search(recv)
        if mo:
            hostname = mo.group(2)

    host, created = Host.objects.get_or_create(name=hostname)
    return host


def date(msg):
    """Compute the date in the message's Date header"""
    try:
        d = msg['Date']
    except KeyError:
        return datetime.datetime.now()
    mo = re.match(r'^[A-Za-z]{3}, (?P<datetime>.*) (?P<tz>(?P<tzdir>\+|-)(?P<tzhours>\d{2})(?P<tzmins>\d{2})|GMT)$', d)
    if not mo:
        return datetime.datetime.now()

    if mo.group('tz') == 'GMT':
        tzinfo = pytz.UTC
    else:
        offset = int(mo.group('tzdir') + '1') + 60 * int(mo.group('tzhours')) + int(mo.group('tzmins'))
        tzinfo = pytz.FixedOffset(offset)

    dt = datetime.datetime.strptime(mo.group('datetime'), '%d %b %Y %H:%M:%S')
    return tzinfo.localize(dt).astimezone(pytz.UTC).replace(tzinfo=None)


def import_mail(s):
    """Parse str as an e-mail and insert it into the database"""
    s = s.strip()
    fp = FeedParser()
    fp.feed(s)
    m = fp.close() 

    
    msg = Message(message=s)
    msg.subject = m.get('Subject', '')
    msg.date = date(m)
    msg.host = find_host(m)

    body = msg.text_body()
    msg.body = truncatelines(body, 1000)
    msg.sha1 = sha1(body.encode('utf8')).hexdigest()

    dupes = Message.objects.filter(host=msg.host, sha1=msg.sha1, status='-').order_by('-received')
    if dupes.count():
        orig = dupes[0]
        orig.add_log_message("Duplicate received dated %s" % msg.date, type='receipt')
    else:
        msg.save()
        msg.add_log_message("Notification received", type='receipt')

        tag(msg)
        filter(msg)
